/**
*    Copyright (C) 2008  Chase Kernan 
*    chase.kernan@gmail.com
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
*/

package com.chasekernan.hxnova.core.dataholders;

import com.chasekernan.hxnova.core.stars.Star;
import com.chasekernan.hxnova.utils.Vector;

/**
    Holds all of the known data about all stars.
**/
class StarsHolder {
    
    public var stars : Array<Star>;
    
    /**
        Can be based of a previous set of star data (such as a map).
        If [s] is not given, and [Global.map] is defined, then the stars array 
        is filled with nulls up to the number of stars defined by the map.
    **/
    public function new(?s : Array<Star>) {
        stars = new Array();
        if(s != null) {
            for(i in s) addStar(i);
        } else if(Global.map != null) {
            for(i in 0...Global.map.stars.length) stars.push(null);
        }
    }
    
    /**
        Will throw an error if the id is out of range.
        If [Global.map] is defined, and the data here is [null], then it will 
        return the map data.
    **/
    public function getStarById(id : Int) : Star {
        if (id < 0 || id >= stars.length) throw "Id# is out of range: " + id;
        if (stars[id] == null && Global.map != null)
            return Global.map.stars[id];
        
        return stars[id];
    }
    
    public function addStar(s : Star) {
        s.id = stars.length;
        stars.push(s);
    }
    
    /**
        Returns the star at the given location (or null if there isnt one).
    **/
    public function getStarAtLocation(location : Vector) : Star {
        for (s in stars) {
            if (location.equals(s.location)) return s;
        }
        
        return null;
    }
    
    
    public static var XML_TITLE = "stars";
    
    public static function writeToXml(sh : StarsHolder) : Xml {
        var xml = Xml.parse('<' + XML_TITLE + '></' + XML_TITLE + '>')
                .firstChild();
        xml.set('num_stars', Std.string(sh.stars.length));
        
        for (s in sh.stars) {
            if(s == null) continue;
            xml.addChild(Star.writeToXml(s));
            xml.addChild(Xml.createElement("spacer"));
        }
        
        return xml;
    }
        
    public static function readFromXml(xml : Xml) : StarsHolder {
        try {
            var sh = new StarsHolder();
            var nullIDs = new Array<Star>();
            
            sh.stars = new Array();
            var length = Std.parseInt(xml.get('num_stars'));
            for(i in 0...length) sh.stars.push(null);
            
            for (e in xml.elementsNamed(Star.XML_TITLE)) {
                var s = Star.readFromXml(e);
                
                //TODO: Id should never be null, but this deals with that 
                //special case.
                if(s.id == null) nullIDs.push(s);
                else sh.stars[s.id] = s;
            }
            
            for(s in nullIDs) sh.addStar(s);
            
            return sh;
        } catch (e : Dynamic) {
            throw "Error while reading stars file from xml: " + e;
        }
    }
    
    public function iterator() {
        return stars.iterator();
    }
    
    /**
        Copies the structure holding the stars, but not the star data itself.
    **/
    public function clone() : StarsHolder {
        var sh = new StarsHolder();
        sh.stars = stars.copy();
        return sh;
    }
}